﻿
namespace CmdArgs.Settings
{
    using System.Collections.Generic;
    using System.Linq;

    /// <summary>
    /// Sice <see cref="CmdArgs.Settings.Settings"/> class is immutable, 
    /// it's construction may be easily done using this builder.
    /// This builder adopts so called fluent interface.
    /// </summary>
    public sealed class SettingsBuilder
    {
        private IList<OptionSettingsBuilder> optionSettingsBuilders = new List<OptionSettingsBuilder>();

        /// <summary>
        /// Creates the <see cref="CmdArgs.Settings.Settings"/> object from
        /// configured values.
        /// </summary>
        /// <returns>The result of building <see cref="CmdArgs.Settings.Settings"/>.</returns>
        public Settings ToSettings()
        {
            return new Settings(
                this.optionSettingsBuilders.Select(b => b.ToOptionSettings()));
        }

        /// <summary>
        /// Adds the option configuration to the options settings list.
        /// Option settings might contain several aliases, values validators,
        /// default value and description for help purposes.
        /// </summary>
        /// <param name="longName">The long name of the option.</param>
        /// <param name="shortName">The short name of the option.</param>
        /// <param name="parametersCount">The parameters count policy.
        /// Use the factory methods on class <see cref="OptionParametersCount"/></param>
        /// <returns>
        /// The <see cref="OptionSettingsBuilder"/> instance
        /// for fluent configuration of other settings of the option
        /// </returns>
        public OptionSettingsBuilder AddOption(string longName, char shortName, IOptionParametersCount parametersCount)
        {
            var optionBuilder = new OptionSettingsBuilder(longName, shortName, parametersCount);
            this.optionSettingsBuilders.Add(optionBuilder);
            return optionBuilder;
        }

        /// <summary>
        /// Overload of method <see cref="AddOption"/>.
        /// </summary>
        /// <param name="longName">The long name of the option.</param>
        /// <param name="parametersCount">The parameters count policy.
        /// Use the factory methods on class <see cref="OptionParametersCount"/></param>
        /// <returns>
        /// The <see cref="OptionSettingsBuilder"/> instance
        /// for fluent configuration of other settings of the option
        /// </returns>
        public OptionSettingsBuilder AddOptionWithLongName(string longName, IOptionParametersCount parametersCount)
        {
            var optionBuilder = new OptionSettingsBuilder(longName, parametersCount);
            this.optionSettingsBuilders.Add(optionBuilder);
            return optionBuilder;
        }

        /// <summary>
        /// Overload of method <see cref="AddOption"/>.
        /// </summary>
        /// <param name="shortName">The short name of the option.</param>
        /// <param name="parametersCount">The parameters count policy.
        /// Use the factory methods on class <see cref="OptionParametersCount"/></param>
        /// <returns>
        /// The <see cref="OptionSettingsBuilder"/> instance
        /// for fluent configuration of other settings of the option
        /// </returns>
        public OptionSettingsBuilder AddOptionWithShortName(char shortName, IOptionParametersCount parametersCount)
        {
            var optionBuilder = new OptionSettingsBuilder(shortName, parametersCount);
            this.optionSettingsBuilders.Add(optionBuilder);
            return optionBuilder;
        }

        /// <summary>
        /// Flag is an option without parameters.
        /// This is overload of the method <see cref="AddOption"/>.
        /// </summary>
        /// <param name="longName">The long name of the flag.</param>
        /// <param name="shortName">The short name of the flag.</param>
        /// <returns>
        /// The <see cref="OptionSettingsBuilder"/> instance
        /// for fluent configuration of other settings of the option
        /// </returns>
        public OptionSettingsBuilder AddFlag(string longName, char shortName)
        {
            var optionBuilder = new OptionSettingsBuilder(longName, shortName, OptionParametersCount.NoParameters());
            this.optionSettingsBuilders.Add(optionBuilder);
            return optionBuilder;            
        }

        /// <summary>
        /// Flag is an option without parameters.
        /// This is overload of the method <see cref="AddFlag"/>.
        /// </summary>
        /// <param name="shortName">The short name of the flag.</param>
        /// <returns>
        /// The <see cref="OptionSettingsBuilder"/> instance
        /// for fluent configuration of other settings of the option
        /// </returns>
        public OptionSettingsBuilder AddFlagWithShortName(char shortName)
        {
            var optionBuilder = new OptionSettingsBuilder(shortName, OptionParametersCount.NoParameters());
            this.optionSettingsBuilders.Add(optionBuilder);
            return optionBuilder;            
        }

        /// <summary>
        /// Flag is an option without parameters.
        /// This is overload of the method <see cref="AddOption"/>.
        /// </summary>
        /// <param name="longName">The long name of the flag.</param>
        /// <returns>
        /// The <see cref="OptionSettingsBuilder"/> instance
        /// for fluent configuration of other settings of the option
        /// </returns>
        public OptionSettingsBuilder AddFlagWithLongName(string longName)
        {
            var optionBuilder = new OptionSettingsBuilder(longName, OptionParametersCount.NoParameters());
            this.optionSettingsBuilders.Add(optionBuilder);
            return optionBuilder;
        }
    }
}
